package com.acme.bankapp.domain.bank;

/**
 * This class defines checking account with overdraft.
 * @author Artem Nikitin
 *
 */
public class CheckingAccount extends AbstractAccount {

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		long temp;
		temp = Double.doubleToLongBits(overdraft);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		temp = Double.doubleToLongBits(overdraftLimit);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		CheckingAccount other = (CheckingAccount) obj;
		if (Double.doubleToLongBits(overdraft) != Double
				.doubleToLongBits(other.overdraft))
			return false;
		if (Double.doubleToLongBits(overdraftLimit) != Double
				.doubleToLongBits(other.overdraftLimit))
			return false;
		return true;
	}

	private double overdraft;
	private double overdraftLimit;

	public CheckingAccount(int id, double balance) {
		super(id, balance);
	}

	/**
	 * Deposits specified amount of funds. If overdraft is positive it discharge the debt at first
	 * @param amount - amount of funds to deposit
	 * @throws IllegalArgumentException - If {@code amount} is negative
	 */
	public void deposit(double amount) {
		if (amount < 0) {
			throw new IllegalArgumentException("Amount cannot be negative");
		}
		
		if (overdraft > amount) {
			overdraft -= amount;
		} else {
			this.balance += amount - overdraft;
			overdraft = 0;
		}
	}

	/**
	 * Withdraw specified amount of funds. If there isn't enough funds to withdraw overdraft starts growing
	 * @param amount - amount of funds to withdraw
	 * @throws OverdraftLimitExceededException - if overdraft limit is exceeded
	 * @throws IllegalArgumentException - if {@code amount} is negative
	 */
	public void withdraw(double amount) throws OverdraftLimitExceededException {
		if (amount < 0) {
			throw new IllegalArgumentException("Amount cannot be negative");
		}
		
		if (maxAmountToWithdraw() < amount) {
			throw new OverdraftLimitExceededException(amount);
		}
		if (getBalance() < amount) {
			this.overdraft = amount - getBalance();
			this.balance = 0;
		} else {
			this.overdraft = 0;
			this.balance -= amount; 
		}
		
	}

	public double getOverdraft() {
		return overdraft;
	}

	public double getOverdraftLimit() {
		return overdraftLimit;
	}

	/**
	 * Sets overdraft limit
	 * @param overdraftLimit - new overdraft limit.
	 * @throws IllegalArgumentException - if {@code overdraftLimit} is negative
	 */
	public void setOverdraftLimit(double overdraftLimit) {
		if (overdraftLimit < 0) {
			throw new IllegalArgumentException("Overdraft limit cannot be negative");
		}
		this.overdraftLimit = overdraftLimit;
	}

	public double maxAmountToWithdraw() {
		return overdraftLimit + balance - overdraft;
	}

}
